package org.graph;

import java.awt.CardLayout;
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * Designed for replacing JFrame (actually, this class extends JFrame) in
 * order to easily manage screen-navigation-based applications. Each 'screen' is
 * represented as a {@link java.awt.Component} object. Therefore, it's not possible to
 * add two 'screens' of the same class. If required, it is necessary to create a
 * new class which extends the previous one, for each of the two (or more)
 * screens supposed to be added.
 *
 * @author See <a href="the Google Code page of the easy-utils
 * library">http://code.google.com/p/easy-utils/</a> for collaborators and other
 * information.
 */
public final class JScreenManager extends JFrame {

    private JPanel screensContainer = new JPanel(new CardLayout());
    private int currentIndex = 0;

    /**
     * Constructs a new default (without screens) JScreenManager.
     */
    public JScreenManager() {
        this.getContentPane().add(this.screensContainer);
    }

    /**
     * Constructs a new JScreenManager object containing a Component that will
     * act as main screen.
     *
     * @param initialScreen {@link Component} The Component that will act as
     * main screen in this JScreenManager object.
     */
    public JScreenManager(Component initialScreen) {
        this.screensContainer.add(initialScreen);
        this.getContentPane().add(this.screensContainer);
    }

    /**
     * Updates the component itself in order to show the screen which type
     * corresponds to the given one.
     *
     * @param targetScreenClass {@link Class} The type of the screen to show.
     */
    public void showScreen(Class<?> targetScreenClass) {
        boolean noSuchComponentFlag = false;

        for (Component current : this.screensContainer.getComponents()) {
            if (current.getClass() == targetScreenClass) {
                noSuchComponentFlag = true;
            }
        }

        if ((!noSuchComponentFlag) || (this.getComponentCount() != 0)) {
            while (this.screensContainer.getComponent(this.currentIndex).getClass() != targetScreenClass) {
                {
                    this.currentIndex++;
                    if (this.currentIndex == this.screensContainer.getComponentCount()) {
                        this.currentIndex = 0;
                    }
                    ((CardLayout) (this.screensContainer.getLayout())).next(this.screensContainer);
                }
            }
        }
    }

    /**
     * Adds a new component to the current set of 'screens'. If there's already
     * a component of the same class than the new one, it won't be added for
     * consistency reasons.
     *
     * @param toAdd {@link Component} The new component to add.
     */
    protected void addScreen(Component toAdd) {
        for (Component current : this.screensContainer.getComponents()) {
            if (current.getClass() == toAdd.getClass()) {
                return;
            }
        }

        this.screensContainer.add(toAdd);
    }

    /**
     * Removes a component from the current set of 'screens'. If there aren't any
     * components matching the class of the component to remove, or the current
     * screen is the component that should be removed, nothing will be
     * removed.
     *
     * @param toRemove {@link Component} The component to remove.
     */
    protected void removeScreen(Component toRemove) {
        try {
            if (toRemove != this.screensContainer.getComponent(this.currentIndex)) {
                this.screensContainer.remove(toRemove);
            }
        } catch (IndexOutOfBoundsException ex) {
        }
    }
}
